/* *************************************************************
 *  renombrar funcion para generar agrupamiento de funciones relacionadas.
 *
 *  ale 26/03/2019
 *
 * se pretende esto
 * ALTER FUNCTION [IF EXISTS] public.verificartotalesxpiva(idcomtotiva integer, character varying) RENAME TO com_verificartotalesxpiva;
 * pero el IF EXISTS no esta disponible para este caso entonces se hacer CREATE OR REPLACE FUNCTION y luego DROP FUCNTION IF EXISTS
 *
 *
 ************************************************************* */

-- Function: public.com_verificartotalesxpiva(integer, character varying)

-- DROP FUNCTION public.com_verificartotalesxpiva(integer, character varying);

CREATE OR REPLACE FUNCTION public.com_verificartotalesxpiva(
    idcomtotiva integer,
    character varying)
  RETURNS character varying AS
$BODY$
-- Recibe como parametros:
-- - el idcomtotiva de las reglas de desvios de IVA a aplicar
-- - un string de la sig. forma:  tasa, netogravado, montoiva; tasa, netogravado, montoiva; ....; 
-- Nota: netogravado y montoiva son siempre positivos
-- Retorna un string: tasa, errornivel, errormensaje, erroridevento; tasa, errornivel, errormensaje, erroridevento; ....;
-- Niveles de error:
--  100: solo lo maneja la funcion. Son los errores que luego AFIP controla en CITI-Compras, CITI-ventas.
--       La app NO permite grabar un comm cuyos totales de IVA arrojen esta categoria de errores.
--  (50, 100): errores definibles en comtotivadet. La app NO permite grabar un comm cuyos totales de IVA
--             arrojen esta categoria de errores. 
--  (0,50]: advertencias definibles en comtotivadet. Se puede asociar un evento comtotivadet.idambacn y
--          controlar el error con ese evento. Si no se asocia evento, la app permite grabar un comm
--          cuyos totales de IVA arrojen este error. 
--  0: Sin error
DECLARE
pIdComTotIva ALIAS FOR $1;
pCadenaIVAs  ALIAS FOR $2;
/*
CREATE TEMP TABLE totivadet_tmp AS 
SELECT * FROM comtotivadet WHERE idcomtotiva = pIdComTotIva;
*/
vCabeza varchar;
vCola varchar;
vPos int4;
vRta varchar;
vTasa numeric(16, 2);
vNetoGravado numeric(16, 2);
vMontoIVA numeric(16, 2);
vAuxMontoIVA  numeric(16, 2); 
vDesvioIVAPesos numeric(16, 2);
vdesvioIVAPorc  numeric(16, 4);
vCursorAbierto varchar;

-- valores de la rta
vErrNivel int4;
vErrMsg varchar;
vErrIdEv  int4;
-- cursor 
comtotivadet_reg comtotivadet%ROWTYPE;
comtotivadet_cursor refcursor;
BEGIN
vCursorAbierto := 'N';
vRta := '';
vCola := TRIM(pCadenaIVAs);
WHILE (LENGTH(vCola) > 0) LOOP
-- Parsear cadenaIVAs para cortar cada grupo (tasa, netogravado, montoiva).
  vPos := strpos(vCola, ';');
  IF (vPos = 0) THEN
    vCabeza := vCola;
    vCola   := '';
  ELSE
    vCabeza := trim(substr(vCola, 1, vPos-1));
    vCola   := trim(substr(vCola, vPos+1, length(vCola)));
  END IF;

  vPos := strpos(vCabeza, ',');

  EXIT WHEN vPos = 0; -- si no encuentra el separador sale del while

-- Separa tasa, netrogravado y montoIVA en variables.
  SELECT split_part(vCabeza, ',', 1) ::NUMERIC(16,2),
         split_part(vCabeza, ',', 2) ::NUMERIC(16,2),
         split_part(vCabeza, ',', 3) ::NUMERIC(16,2) INTO vTasa, vNetoGravado, vMontoIVA;
  vErrNivel := NULL;
  vErrMsg   := '';
  vErrIdEv  := -1;

-- verifica los valores para la tasa de iva
  IF (vNetoGravado <> 0.00) OR (vMontoIVA <> 0.00) THEN
-- ======== Errores que controla AFIP =========
-- AFIP caso 1: hay Neto gravado y falta IVA
    IF (vNetoGravado <> 0.00) AND (vMontoIVA = 0.00) THEN
      vErrNivel := 100;
      vErrMsg   := 'El IVA no puede ser cero.';
    END IF;

-- AFIP caso 2: Neto gravado < IVA (se comparan valores sin signo)
    IF (vErrNivel IS NULL) AND (vNetoGravado < vMontoIVA) THEN
       vErrNivel := 100;
       vErrMsg   := 'El IVA no puede ser mayor que el Neto gravado.';
    END IF;  

-- ======== errores por desvio del IVA =========
-- caso 3: ver si (Neto gravado * tasa) y MontoIVA cumples los desvios permitidos
--  verificartotalesxpiva_desvioiva()
--raise NOTICE '   vErrNivel=%',vErrNivel;

    IF (vErrNivel IS NULL) AND (pidcomtotiva IS NOT NULL) THEN
  -- calcular desvios del monto de IVA a controlar
       vAuxMontoIVA   := abs(vNetoGravado * vTasa / 100);
       vdesvioIVAPesos := abs(vAuxMontoIVA - vMontoIVA);  
       vdesvioIVAPorc  := abs(100.00 - (vMontoIVA*10000/(vNetoGravado * vTasa)));  
     /*
     raise NOTICE '   vTasa=%',vTasa;
     raise NOTICE '   vNetoGravado=%',vNetoGravado;
     raise NOTICE '   vMontoIVA=%',vMontoIVA;
     raise NOTICE '   vAuxMontoIVA=%',vAuxMontoIVA;
     raise NOTICE '   vdesvioIVAPesos=%',vdesvioIVAPesos;
     raise NOTICE '   vdesvioIVAPorc=%',vdesvioIVAPorc;
     */     
     -- abrir cursor si esta cerrado

      IF (vCursorAbierto = 'N') THEN
         OPEN comtotivadet_cursor SCROLL   
           FOR ( SELECT * FROM comtotivadet WHERE comtotivadet.idcomtotiva = pidcomtotiva ORDER BY comtotivadet.nivelerror DESC ); 
         vCursorAbierto := 'S';
      END IF;  

      FETCH FIRST FROM comtotivadet_cursor INTO comtotivadet_reg;

      LOOP EXIT WHEN (NOT FOUND) OR (vErrNivel IS NOT NULL);

    -- procesar cada una de las filas: el desvio debe cumplir comtotaivadet.desviopesos OR comtotaivadet.desvioporc
    -- comtotaivadet.desvio/comtotaivadet.desvioporc = NULL -> no se controla
        IF NOT ( ((comtotivadet_reg.desvioPesos IS NULL) OR (vdesvioIVAPesos <= comtotivadet_reg.desvioPesos)) AND
                 ((comtotivadet_reg.desvioPorc IS NULL) OR (vdesvioIVAPorc <= comtotivadet_reg.desvioPorc)) ) THEN
           vErrNivel := comtotivadet_reg.nivelerror;
           vErrIdEv  := comtotivadet_reg.idambacn;
 
           --verificar si se cumple el hay desvio en pesos       
           IF (comtotivadet_reg.desvioPesos IS NOT NULL) AND (vdesvioIVAPesos > comtotivadet_reg.desvioPesos) THEN
             vErrMsg := 'La diferencia en el IVA (' || vdesvioIVAPesos || ' $) supera el importe permitido (' || comtotivadet_reg.desvioPesos || ' $).';
           ELSE
          --si el desvio en pesos es valido -> desvio en porcentaje
          --IF (comtotivadet_reg.desvioPorc IS NOT NULL) AND (vDesvioIVAPorc > comtotivadet_reg.desvioPorc) THEN
             vErrMsg := 'La diferencia en el IVA (' || vdesvioIVAPorc || ' %) supera el porcentaje permitido (' || comtotivadet_reg.desvioPorc || ' %).';
           END IF; 
        END IF; 

        FETCH NEXT FROM comtotivadet_cursor INTO comtotivadet_reg;

      END LOOP;

    END IF;

  END IF;

  -- arma cadena de respuesta 
  vRta := vRta || (vTasa)::varchar || ',' || COALESCE(vErrNivel, 0)::varchar || ',' ||
          COALESCE(vErrMsg, '')           || ',' ||
          COALESCE(vErrIdEv, -1)::varchar || ';';

END LOOP;

RETURN vRta;

END;$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION public.com_verificartotalesxpiva(integer, character varying) OWNER TO abacouser;

-- se borra la anterior si existe
DROP  FUNCTION IF EXISTS public.verificartotalesxpiva(idcomtotiva integer, character varying);

-- =====================================
SELECT aaversion('403.00');
-- =====================================
